package com.freecycle.sg.utils;

import java.util.List;
import java.util.Locale;

import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.location.Address;
import android.location.Criteria;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationManager;
import android.location.LocationProvider;
import android.os.AsyncTask;
import android.preference.PreferenceManager;

import com.google.android.maps.GeoPoint;

public class LocationHelper {

	private static final int MAX_RESULTS = 10;

	private static Context context;
	private LocationManager manager;
	private LocationProvider lowAccProvider;
	private LocationProvider highAccProvider;

	public LocationHelper(Context context) {
		this.context = context;
		manager = (LocationManager) context
				.getSystemService(Context.LOCATION_SERVICE);
		// get low accuracy provider
		lowAccProvider = manager.getProvider(manager.getBestProvider(
				createCoarseCriteria(), true));
		// get high accuracy provider
		highAccProvider = manager.getProvider(manager.getBestProvider(
				createFineCriteria(), true));
	}

	/**
	 * this criteria will settle for less accuracy, power, and cost (Cell-Id,
	 * Wifi)
	 */
	private static Criteria createCoarseCriteria() {
		Criteria c = new Criteria();
		c.setAccuracy(Criteria.ACCURACY_COARSE);
		c.setAltitudeRequired(false);
		c.setBearingRequired(false);
		c.setSpeedRequired(false);
		c.setCostAllowed(true);
		c.setPowerRequirement(Criteria.POWER_HIGH);
		return c;
	}

	/** this criteria will settle for high accuracy, power, and cost (GPS, AGPS) */
	private static Criteria createFineCriteria() {
		Criteria c = new Criteria();
		c.setAccuracy(Criteria.ACCURACY_FINE);
		c.setAltitudeRequired(false);
		c.setBearingRequired(false);
		c.setSpeedRequired(false);
		c.setCostAllowed(true);
		c.setPowerRequirement(Criteria.POWER_HIGH);
		return c;
	}

	public List<Address> reverseGeoCoding(Location loc) {
		double latitude = loc.getLatitude();
		double longitude = loc.getLongitude();

		Geocoder engine = new Geocoder(context, Locale.getDefault());
		try {
			List<Address> list = engine.getFromLocation(latitude, longitude,
					MAX_RESULTS);
			return list;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	public LocationManager getLocationManager() {
		return manager;
	}

	public LocationProvider getLowAccProvider() {
		return lowAccProvider;
	}

	public LocationProvider getHighAccProvider() {
		return highAccProvider;
	}

	public static boolean isCurrentLocationAvailable() {
		SharedPreferences sp = PreferenceManager
				.getDefaultSharedPreferences(context);
		return sp.getBoolean(Config.IS_CURRENT_LOCATION_AVAILABLE, false);
	}

	public static void setCurrentLocation(final Location location) {
		new AsyncTask<Void, Void, Void>() {
			@Override
			protected Void doInBackground(Void... voids) {
				SharedPreferences sp = PreferenceManager
						.getDefaultSharedPreferences(context);
				Editor editor = sp.edit();
				editor.putFloat(Config.CURRENT_LATITUDE,
						(float) location.getLatitude());
				editor.putFloat(Config.CURRENT_LONGITUDE,
						(float) location.getLongitude());
				editor.putBoolean(Config.IS_CURRENT_LOCATION_AVAILABLE, true);
				editor.commit();
				return null;
			}
		}.execute();
	}

	public static GeoPoint getCurrentLocation(final Context context) {
		SharedPreferences sp = PreferenceManager
				.getDefaultSharedPreferences(context);
		if (sp.getBoolean(Config.IS_CURRENT_LOCATION_AVAILABLE, false)) {
			double latitude = sp.getFloat(Config.CURRENT_LATITUDE,
					(float) Config.sgLatitude);
			double longitude = sp.getFloat(Config.CURRENT_LONGITUDE,
					(float) Config.sgLongitude);
			return new GeoPoint((int) (latitude * 1e6), (int) (longitude * 1e6));
		} else {
			return null;
		}
	}

}
